#include "modbusslave.h"
#include "ui_modbusslave.h"
#include <QDebug>

using namespace std;

modbusSlave::modbusSlave(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::modbusSlave)
{
    ui->setupUi(this);

     m_mode=Tcp;

    if(m_mode==Tcp)
       m_slave = new QModbusTcpClient(this);
    else
       m_slave = new QModbusRtuSerialMaster(this);

    if (ui->IP->text().isEmpty())
        ui->IP->setText(QLatin1Literal("127.0.0.1"));
    if (ui->Port->text().isEmpty())
        ui->Port->setText(QLatin1Literal("502"));
    ui->address->setText("1");

    connect(m_slave, &QModbusClient::stateChanged,
            this, &modbusSlave::onStateChanged);//连接状态发生改变时改变connect按钮上的显示文字（connect or discennect）
    connect(m_slave, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
        statusBar()->showMessage(m_slave->errorString(), 5000);
    });
}

modbusSlave::~modbusSlave()
{
    if (m_slave)
        m_slave->disconnectDevice();
    delete m_slave;
    delete ui;
}


bool modbusSlave::initModbusSerialSlave(QString portName, qint32 baudRate,
                                         QSerialPort::DataBits dataBits,
                                         QSerialPort::Parity parity,
                                         QSerialPort::StopBits stopBits)
{
  //  m_slave = new QModbusRtuSerialMaster(this);

    if(!m_slave)
    {
        return 0;
    }
    m_slave->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
                                    portName);
    m_slave->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
                                    baudRate);
    m_slave->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
                                    dataBits);
    m_slave->setConnectionParameter(QModbusDevice::SerialParityParameter,
                                    parity);
    m_slave->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
                                    stopBits);
    return 1;
}

bool modbusSlave::initModbusNetworkSlave(QString address, int port)
{
  //  m_slave = new QModbusTcpClient(this);
    m_mode = Tcp;

    if(!m_slave)
    {
        qDebug()<<"init master error";
        return 0;
    }
    m_slave->setConnectionParameter(QModbusDevice::NetworkAddressParameter,
                                    address);
    m_slave->setConnectionParameter(QModbusDevice::NetworkPortParameter,
                                    port);
    return 1;

}

bool modbusSlave::connectDevice()
{
    return m_slave->connectDevice();
}


bool modbusSlave::writeRegisterData(QString str, int startAddress, int num)
{
    QByteArray byte = QByteArray::fromHex(str.toLatin1().data());
    QString hexStr = byte.toHex().data();

    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters
                              ,startAddress,num);

    for(int i = 0;i < writeUnit.valueCount(); i++)
    {
        int j = 2*i;
        QString str = hexStr.mid(j,2);

        bool ok;
        int hex = str.toInt(&ok,16);

        writeUnit.setValue(i,hex);
    }

    //1 代表server address sendWriteRequest 是想服务器写数据
    if(auto* reply = m_slave->sendWriteRequest(writeUnit,ui->address->text().toInt()))
    {
        if(!reply->isFinished())
        {
            connect(reply,&QModbusReply::finished,this,[this,reply]()
            {
                if(reply->error() == QModbusDevice::ProtocolError)
                {
                    qDebug()<<"write response ProtocolError:"<<reply->errorString();
                    return 0;
                }
                else if(reply->error() != QModbusDevice::NoError)
                {
                    qDebug()<<"write response error:"<<reply->errorString();
                    return 0;
                }

                reply->deleteLater();
            });
        }
        else
        {
            reply->deleteLater();
            return 1;
        }
    }
    else
    {
        qDebug()<<"write error: "<<m_slave->errorString();
        return 0;
    }


}

void modbusSlave::readRegisterData(int startAddress, int num)
{
    if(!m_slave)
        return;

    QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters,startAddress,num);

    if(auto* reply = m_slave->sendReadRequest(readUnit,ui->address->text().toInt()))
    {
        if(!reply->isFinished())
        {
            connect(reply,&QModbusReply::finished,this,&modbusSlave::readyRead);

        }
        else
        {
            delete reply;
        }

    }
    else
    {
        qDebug()<<m_slave->errorString();
    }
}

void modbusSlave::handleDeviceError(QModbusDevice::Error newError)
{
    if(newError == QModbusDevice::NoError || !m_slave)
        return;
    emit error_signal(m_slave->errorString());
}


void modbusSlave::onStateChanged(int state)
{
    if(state == QModbusDevice::UnconnectedState)
     //   emit stateChanged_signal(0);
         ui->connectButton->setText(tr("Connect"));
    else if(state == QModbusDevice::ConnectedState)
     //   emit stateChanged_signal(1);
         ui->connectButton->setText(tr("Disconnect"));
}


void modbusSlave::readyRead()
{
    auto reply = qobject_cast<QModbusReply *>(sender());//QModbusReply这个类存储了来自client的数据,sender()返回发送信号的对象的指针
    if (!reply)
        return;
//数据从QModbusReply这个类的resuil方法中获取,也就是本程序中的reply->result()
    if (reply->error() == QModbusDevice::NoError) {
        const QModbusDataUnit unit = reply->result();
        for (uint i = 0; i < unit.value(10); i++) {//unit.valueCount()
//            const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress())
//                                     .arg(QString::number(unit.value(i),
//                                          unit.registerType() <= QModbusDataUnit::Coils ? 10 : 16));

            ui->textEdit->append(QString::number(unit.value(i),16));
        }
    } else if (reply->error() == QModbusDevice::ProtocolError) {
        statusBar()->showMessage(tr("Read response error: %1 (Mobus exception: 0x%2)").
                                    arg(reply->errorString()).
                                    arg(reply->rawResult().exceptionCode(), -1, 16), 5000);
    } else {
        statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)").
                                    arg(reply->errorString()).
                                    arg(reply->error(), -1, 16), 5000);
    }

    reply->deleteLater();
}





void modbusSlave::on_connectButton_clicked()
{
    if (!m_slave)
        return;
    statusBar()->clearMessage();

    if (m_slave->state() != QModbusDevice::ConnectedState) {//如果处在非连接状态，进行连接

        initModbusNetworkSlave(ui->IP->text(),ui->Port->text().toInt());
        m_slave->setTimeout(1000);//连接超时1S
        m_slave->setNumberOfRetries(3);//连接失败重试三次连接
        if (!m_slave->connectDevice()) {
            statusBar()->showMessage(tr("Connect failed: ") + m_slave->errorString(), 5000);
        }
    }else{//处在连接状态进行断开连接的操作
        m_slave->disconnectDevice();
    }
}

void modbusSlave::on_sendButton_clicked()
{
    stringstream convert;
    union client
    {
      float Data[6];//longitude,latiude,Dive,Pitch,Roll,Yaw
      quint16 send_data[13];//第13位用作判断信号来源
    }Udata;

    if (!m_slave)//如果设备没有被创建就返回
        return;

    /******数据处理转化******/
    string stri[6];
     stri[0] = ui->longitude->text().toStdString();
     stri[1] = ui->latitude->text().toStdString();
     stri[2] = ui->Dive->text().toStdString();
     stri[3] = ui->Pitch->text().toStdString();
     stri[4] = ui->Roll->text().toStdString();
     stri[5] = ui->Yaw->text().toStdString();

    for(int i=0;i<6;i++)
    {
        convert.clear();
        convert.str("");
        convert.str(stri[i]);
        convert >>setprecision(8)>> Udata.Data[i];

       qDebug()<<Udata.Data[i]<<endl;

    }
    Udata.send_data[12] = 255;

    statusBar()->clearMessage();//清除状态栏显示的信息
    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters,0,13);//发送的数据信息（数据类型 ，起始地址，个数）
//    QModbusDataUnit::RegisterType table = writeUnit.registerType();//得到寄存器类型传给table
    for (uint i = 0; i < writeUnit.valueCount(); i++)
    {
        writeUnit.setValue(i,Udata.send_data[i]);//设置发送数据为123456789
     //   qDebug()<<Udata.send_data[i]<<endl;
    }
 //   auto *reply = modbusDevice->sendWriteRequest(writeUnit, 1);//发送数据 1是server address
    if (auto *reply = m_slave->sendWriteRequest(writeUnit, ui->address->text().toInt())) {
        if (!reply->isFinished()) {   //reply Returns true when the reply has finished or was aborted.
            connect(reply, &QModbusReply::finished, this, [this, reply]() {
                if (reply->error() == QModbusDevice::ProtocolError) {
                    statusBar()->showMessage(tr("Write response error: %1 (Mobus exception: 0x%2)")
                        .arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16),
                        5000);
                } else if (reply->error() != QModbusDevice::NoError) {
                    statusBar()->showMessage(tr("Write response error: %1 (code: 0x%2)").
                        arg(reply->errorString()).arg(reply->error(), -1, 16), 5000);
                }
                reply->deleteLater();
            });
        } else {
            // broadcast replies return immediately
            reply->deleteLater();
        }
    } else {
        statusBar()->showMessage(tr("Write error: ") + m_slave->errorString(), 5000);
    }
}

void modbusSlave::on_receiveButton_clicked()
{

  readRegisterData(0,11);

}
